package org.gpslw.supermap;

import org.geotools.data.wfs.WFSDataStore;
import org.geotools.data.wfs.WFSDataStoreFactory;
import org.geotools.data.wfs.internal.WFSClient;
import org.geotools.data.wfs.internal.WFSConfig;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.feature.type.FeatureTypeFactoryImpl;
import org.geotools.http.HTTPClient;
import org.geotools.http.HTTPClientFinder;
import org.geotools.http.HTTPConnectionPooling;
import org.geotools.ows.ServiceException;
import org.geotools.util.factory.Hints;
import org.locationtech.jts.geom.GeometryFactory;
import org.locationtech.jts.geom.impl.PackedCoordinateSequenceFactory;

import java.io.IOException;
import java.net.URL;
import java.util.Map;

public class SuperMapWfsDataStoreFactory extends WFSDataStoreFactory {


    public WFSDataStore createDataStore(Map<String, ?> params) throws IOException {

        WFSConfig config = WFSConfig.fromParams(params);
        String user = config.getUser();
        String password = config.getPassword();
        if ((user != null || password == null) && (config.getPassword() != null || config.getUser() == null)) {
            URL capabilitiesURL = (URL)URL.lookUp(params);
            HTTPClient http = this.getHttpClient(params);
            http.setTryGzip(config.isTryGZIP());
            http.setUser(config.getUser());
            http.setPassword(config.getPassword());
            int timeoutMillis = config.getTimeoutMillis();
            http.setConnectTimeout(timeoutMillis / 1000);
            http.setReadTimeout(timeoutMillis / 1000);

            WFSClient wfsClient;
            try {
                wfsClient = new WFSClient(capabilitiesURL, http, config);
            } catch (ServiceException e) {
                throw new IOException(e);
            }

            WFSDataStore dataStore = new SuperMapWfsDataStore(wfsClient);
            dataStore.setFilterFactory(CommonFactoryFinder.getFilterFactory((Hints)null));
            dataStore.setGeometryFactory(new GeometryFactory(PackedCoordinateSequenceFactory.DOUBLE_FACTORY));
            dataStore.setFeatureTypeFactory(new FeatureTypeFactoryImpl());
            dataStore.setFeatureFactory(CommonFactoryFinder.getFeatureFactory((Hints)null));
            dataStore.setDataStoreFactory(this);
            dataStore.setNamespaceURI(config.getNamespaceOverride());
            return dataStore;
        } else {
            throw new IOException("Cannot define only one of USERNAME or PASSWORD, must define both or neither");
        }
    }

    public HTTPClient getHttpClient(Map<String, ?> params) throws IOException {
        WFSConfig config = WFSConfig.fromParams(params);
        if (config.isUseHttpConnectionPooling()) {
            HTTPClient client = HTTPClientFinder.createClient(new Class[]{HTTPConnectionPooling.class});
            client.setReadTimeout(config.getTimeoutMillis() / 1000);
            client.setConnectTimeout(config.getTimeoutMillis() / 1000);
            ((HTTPConnectionPooling)client).setMaxConnections(config.getMaxConnectionPoolSize());
            return client;
        } else {
            return HTTPClientFinder.createClient();
        }
    }
}
